﻿using System;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Deployment.Application;

namespace AppMain
{
    public partial class StartWindow : Form
    {
        // Testing Variables
        bool[] _oldTargetSwitchPositions = { false, false, false, false, false, false, false, false, false, false, false };
        //private Int16 _testingVar;
        //Parameters for Transmitter
        Dictionary<int,SettingsTx> P_TX = new Dictionary<int,SettingsTx>();
        int P_SnmpScanTime;
       
        // Parameters For Meter Page
        RadioButton[] _selector = new RadioButton[SwMatrix.MaximumTransmitterNumber+1];
        List<Meter> _processMeters = new List<Meter>();
        bool _meterPageWasVisible = false;

        //Dictionary for Control of SNMP transmitters
        Dictionary<int, Thompson.Tx> C_TX = new Dictionary<int, Thompson.Tx>();
        //Dictionary for TX User Control
        Dictionary<int, TxUsrCtrl> G_TX = new Dictionary<int, TxUsrCtrl>();

        //Parameters for PLC
        string P_TxPLCIPAddress;
        string P_SwPLCIPAddress;
        int P_TxPlcScanTime;
        int P_SwPlcScanTime;
        TxPlcComm TxPLC = new TxPlcComm();
        SwPlcComm SwPLC = new SwPlcComm();
        TxSwitcher txSwitcher;

        //Instance for writing logs from this file
        LogData log = AppMain.LogData.GetObject;
        int[] retryAttempts = new int[8];
        
        public StartWindow()
        {
            log.Write(string.Format("Started Application {0}", swVersion()));
            //Step 1: Init the GUI
            InitializeComponent();
            //Step 2: Init the Interface
            initInterface();
        }

        private void initInterface()
        {
            /******************************/
            /* Initialize the Application */
            /******************************/
            //Step 1: Read the settings file
            log.Write("Beginning to read Settings File...");
            TxPlcStatus.Text = "Beginning to read Settings File...";
            TxPlcStatus.ForeColor = Color.Black;
//            MeterPage.
            bool l_settingsReadSuccess = false;
            lblSettingsDisplay.Text = readSettings(ref l_settingsReadSuccess);
            log.Write(lblSettingsDisplay.Text);
            if (l_settingsReadSuccess == false)
            {
                TxPlcStatus.Text = "Settings file could not be read. Check log!";
                return;
            }

            //Step 2: Set the TX Communication Control
            foreach (var setting in P_TX)
            {   //Create new transmitter instance for each setting in the parameter file
                int count = G_TX.Count;
                
                //Add the TX Controls to the GUI
                G_TX.Add(setting.Key, new TxUsrCtrl(setting.Key));  //new control buttons instance
                G_TX[setting.Key].Location = new System.Drawing.Point(count * (G_TX[setting.Key].Width + 12)+6, 6); //proper placement in StartWindow tab
                G_TX[setting.Key].chBoxTxIfChanged += new EventHandler(StartWindow_chBoxTxIfChanged); //event for enable/disable the interface
                G_TX[setting.Key].OnChangeRequestInPLC += new TxUsrCtrl.ChangeRequestInPLC(StartWindow_OnChangeRequestInPLC); //event for user to override Burk
                G_TX[setting.Key].updateDisplay(new RequestToTx { GenModulation = false, GenPower = false, Channel=0, PowerRequest=4, ModulationRequest=4 }, P_TX[setting.Key]); //update the text of the buttons to the settings read from file
                TxControlTab.Controls.Add(G_TX[setting.Key]); //add the control to the StartWindow tab
                
                //Start SNMP communications
                C_TX.Add(setting.Key, new Thompson.Tx(setting.Key));   //new class instance
                C_TX[setting.Key].StartCommunication(setting.Value.IPAddress, P_SnmpScanTime); //Start Communication
                C_TX[setting.Key].writeEnabled = G_TX[setting.Key].chBoxTxIF.Checked;
                G_TX[setting.Key].WriteSnmpStatus(C_TX[setting.Key].GuiText); //update status in GUI
            }

            //Step 3: Set the PLC Communication
            TxPLC.StartCommunication(P_TxPLCIPAddress, P_TxPlcScanTime);
            TxPlcStatus.Text = TxPLC.GetStatusText();

            SwPLC.StartCommunication(P_SwPLCIPAddress, P_SwPlcScanTime);
            SwPlcStatus.Text = SwPLC.GetStatusText();

            lblVersion.Text = PublishVersion;
            this.Text += " " + PublishVersion;

            // Add Radio Buttons To Select the appropriate Transmitter
            // to drive the gauges on the Metering Tab
            byte x = 0;
            foreach (int key in P_TX.Keys)
            {
                _selector[key] = new RadioButton();
                _selector[key].Text = "Transmitter" + key.ToString();
                _selector[key].Location = new System.Drawing.Point((13 + (x++*600)/ P_TX.Keys.Count), 377);
                _selector[key].Click += new System.EventHandler(MeterSelect_Click);
                MeterPage.Controls.Add(_selector[key]);
            }
            if (_selector[6] != null)
            {
                _selector[6].Checked = true;
            }
        }   //end void initInterface()

        void StartWindow_OnChangeRequestInPLC(int txNum, TxUsrCtrl.E_BtnType button, object Tag)
        {
            log.Write(string.Format("User requested writing new command for TX {0}: {1} to (value) {2}", txNum.ToString(), button.ToString(), Tag.ToString()));
            // Note: There should be some checking to see if the PLC
            // is being overwritten. I am not sure how to implement this
            // exactly, but it needs to be done.
            //if (!C_TX[txNum].writeEnabled)
            //{
                TxPLC.ChangeRequestToTx(txNum, button, Tag);
            //}
        }

        void StartWindow_chBoxTxIfChanged(object sender, EventArgs e)
        {
            //Allow the user to pass requests from PLC or not
            try
            {
                CheckBox chBx = (CheckBox)sender;
                log.Write(string.Format("User has changed the interface for TX {0} to: ", chBx.Tag.ToString()) + chBx.Text);
                C_TX[Convert.ToInt32(chBx.Tag)].writeEnabled = chBx.Checked;
            }
            catch (Exception) { }
        }

        private string readSettings(ref bool success_b)
        {
            //init success as false
            success_b = false;

            //New string for returning the results
            StringWriter settingstext = new StringWriter();
            settingstext.WriteLine("Settings loaded from file: ThompsonTxInterface.exe.config");

            foreach (string key in ConfigurationManager.AppSettings)
            {
                //Get the value of the parameter in the settings file
                string value = ConfigurationManager.AppSettings[key];
                //split the parameter name into an array using the '_' character
                string[] keysplit = key.Split('_');
                
                //Go here if the parameter is associated with a Transmitter (TX6)
                if (keysplit[0].Equals("TX", StringComparison.CurrentCultureIgnoreCase))
                {
                    //TX Number is in 2nd parse
                    int txNumber = Convert.ToInt32(keysplit[1]);
                    //Check if TX exists yet; add new Tx to settings if does not exist
                    if (P_TX.ContainsKey(txNumber) == false)
                    {
                        //Create a new dummy class with default values that can be checked later
                        P_TX.Add(txNumber, new SettingsTx   {
                                    Name = keysplit[0] + keysplit[1],
                                    IPAddress = null,
                                    ModulationNormal = new Thompson.Tx.E_CommandModulationMode[] 
                                            {Thompson.Tx.E_CommandModulationMode.Unknown, 
                                                Thompson.Tx.E_CommandModulationMode.Unknown, 
                                                Thompson.Tx.E_CommandModulationMode.Unknown, 
                                                Thompson.Tx.E_CommandModulationMode.Unknown},
                                    ModulationGenerator = new Thompson.Tx.E_CommandModulationMode[]
                                            {Thompson.Tx.E_CommandModulationMode.Unknown, 
                                                Thompson.Tx.E_CommandModulationMode.Unknown, 
                                                Thompson.Tx.E_CommandModulationMode.Unknown, 
                                                Thompson.Tx.E_CommandModulationMode.Unknown},
                                    PowerLevelNormal = new int[] {999, 999, 999, 999},
                                    PowerLevelGenerator = new int[] {999,999,999,999},
                                    Modulation = 4});
                    }


                    if (keysplit[2].Equals("Modulation", StringComparison.CurrentCultureIgnoreCase))
                    {
                        //This is a modulation type - add it to the appropriate array
                        Thompson.Tx.E_CommandModulationMode modtype = (Thompson.Tx.E_CommandModulationMode)Convert.ToInt32(value);
                        if (keysplit[4].Equals("Normal", StringComparison.CurrentCultureIgnoreCase))
                        {
                            P_TX[txNumber].ModulationNormal[Convert.ToInt32(keysplit[3])] = modtype;
                        }
                        else if (keysplit[4].Equals("Generator", StringComparison.CurrentCultureIgnoreCase))
                        {
                            P_TX[txNumber].ModulationGenerator[Convert.ToInt32(keysplit[3])] = modtype;
                        }
                        else
                        {
                            //Invalid Modulation
                            string error = string.Format("Error loading setting {0}", key);
                            return error;
                        }
                    }
                    else if (keysplit[2].Equals("Power", StringComparison.CurrentCultureIgnoreCase))
                    {
                        //This is a modulation type - add it to the appropriate array
                        int powerlevel = Convert.ToInt32(value);
                        if (keysplit[4].Equals("Normal", StringComparison.CurrentCultureIgnoreCase))
                        {
                            P_TX[txNumber].PowerLevelNormal[Convert.ToInt32(keysplit[3])] = powerlevel;
                        }
                        else if (keysplit[4].Equals("Generator", StringComparison.CurrentCultureIgnoreCase))
                        {
                            P_TX[txNumber].PowerLevelGenerator[Convert.ToInt32(keysplit[3])] = powerlevel;
                        }
                        else
                        {
                            //Invalid Modulation
                            string error = string.Format("Error loading setting {0}", key);
                            return error;
                        }
                    }
                    else if (keysplit[2].Equals("IPAddress", StringComparison.CurrentCultureIgnoreCase))
                    {
                        //Here is the IP address for the transmitter
                        P_TX[txNumber].IPAddress = value;
                    }
                    else
                    {
                        string error = string.Format("Error loading setting {0}", key);
                        return error;
                    }
                }
                else if (keysplit[0].Equals("TxControlPLC", StringComparison.CurrentCultureIgnoreCase))
                {
                    //Go here if the parameter is for the Transmitter Control PLC
                    if (keysplit[1].Equals("IPAddress", StringComparison.CurrentCultureIgnoreCase))
                    {
                        //This is the IP Address for the Transmitter Control PLC
                        P_TxPLCIPAddress = value;
                    }
                    else  if (keysplit[1].Equals("ScanTime", StringComparison.CurrentCultureIgnoreCase))
                    {
                        //This is the PLC IP Address
                        P_TxPlcScanTime = Convert.ToInt32(value);
                    }
                    else
                    {
                        string error = string.Format("Error loading setting {0}", key);
                        return error;
                    }
                }
                else if (keysplit[0].Equals("SwMatrixPLC", StringComparison.CurrentCultureIgnoreCase))
                {
                    //Go here if the parameter is for the Switch Matrix PLC
                    if (keysplit[1].Equals("IPAddress", StringComparison.CurrentCultureIgnoreCase))
                    {
                        //This is the IP Address for the Switch Matrix PLC
                        P_SwPLCIPAddress = value;
                    }
                    else if (keysplit[1].Equals("ScanTime", StringComparison.CurrentCultureIgnoreCase))
                    {
                        //This is the PLC IP Address
                        P_SwPlcScanTime = Convert.ToInt32(value);
                    }
                    else
                    {
                        string error = string.Format("Error loading setting {0}", key);
                        return error;
                    }
                }
                else if (keysplit[0].Equals("SnmpScanTime", StringComparison.CurrentCultureIgnoreCase))
                {
                    //Load Scan Time here
                    P_SnmpScanTime = Convert.ToInt32(value);
                }
                else if (keysplit[0].Equals("Transmitter", StringComparison.CurrentCultureIgnoreCase))
                {
                    //These are the colors for the transmitters
                    int index = 0;
                    try
                    {
                        index = Convert.ToInt32(keysplit[1]);
                    }
                    catch
                    {
                        string error = string.Format("Error loading setting {0}", key) + " Invalid Transmitter Number";
                    }
                    if (index > 7)
                    {
                        string error = string.Format("Error loading setting {0}", key) + " Only 7 Transmitters Supported";
                        SwMatrix._txColor[index] = Color.SlateGray;
                    }
                    try
                    {
                        SwMatrix._txColor[index] = (Color.FromName(value));
                    }
                    catch
                    {
                        string error = string.Format("Error loading setting {0}", key) + " Invalid Color";
                        SwMatrix._txColor[index] = Color.SlateGray;
                        return error;
                    }
                    if (SwMatrix._txColor[index].ToArgb() == 0)
                    {
                        string error = string.Format("Error loading setting {0}", key) + " Invalid Color";
                        SwMatrix._txColor[index] = Color.SlateGray;
                    }
                }
                else if (keysplit[0].Equals("SwitchPosition", StringComparison.CurrentCultureIgnoreCase))
                {
                    //These are the image files for the switch positions
                    if (keysplit[1].Equals("0", StringComparison.CurrentCultureIgnoreCase))
                    {
                        if (System.IO.File.Exists(value))
                        {
                            SwMatrix.UpdateSwitchGraphicsLocations(SwMatrix.SwitchGraphic.Position0, Path.GetFullPath(value));
                        }
                        else
                        {
                            return string.Format("Error loading Switch Image File '{0}'", value);
                        }
                    }
                    else if (keysplit[1].Equals("1", StringComparison.CurrentCultureIgnoreCase))
                    {
                        if (System.IO.File.Exists(value))
                        {
                            SwMatrix.UpdateSwitchGraphicsLocations(SwMatrix.SwitchGraphic.Position1, Path.GetFullPath(value));
                        }
                        else
                        {
                            return string.Format("Error loading Switch Image File '{0}'", value);
                        }
                    }
                    else if (keysplit[1].Equals("Fault", StringComparison.CurrentCultureIgnoreCase))
                    {
                        if (System.IO.File.Exists(value))
                        {
                            SwMatrix.UpdateSwitchGraphicsLocations(SwMatrix.SwitchGraphic.PositionError, Path.GetFullPath(value));
                        }
                        else
                        {
                            return string.Format("Error loading Switch Image File '{0}'", value);
                        }
                    }
                    else if (keysplit[1].Equals("Moving", StringComparison.CurrentCultureIgnoreCase))
                    {
                        if (System.IO.File.Exists(value))
                        {
                            SwMatrix.UpdateSwitchGraphicsLocations(SwMatrix.SwitchGraphic.Moving, Path.GetFullPath(value));
                        }
                        else
                        {
                            return string.Format("Error loading Switch Image File '{0}'", value);
                        }
                    }
                }
                else if (keysplit[0].Equals("SwitchConfigurationFile", StringComparison.CurrentCultureIgnoreCase))
                {
                    SwMatrix.SwitchCombinationFileError error = SwMatrix.LoadSwitchCombinations(value);
                    switch (error)
                    {
                        case SwMatrix.SwitchCombinationFileError.BadFileName:
                        {
                            return string.Format("Error loading switch configuration File {0}", value);
                        }
                        case SwMatrix.SwitchCombinationFileError.BadTransmitterNumber:
                        {
                            return string.Format("Error loading Transmitter from Line {0} of switch configuration file {1}", SwMatrix._parseLineNumber.ToString(), value);
                        }
                        case SwMatrix.SwitchCombinationFileError.BadAntennaName:
                        {
                            return string.Format("Error loading Antenna from Line {0} of switch configuration file {1}", SwMatrix._parseLineNumber.ToString(), value);
                        }
                        case SwMatrix.SwitchCombinationFileError.BadSwitchNumber:
                        {
                            return string.Format("Error loading Switch from Line {0} of switch configuration file {1}", SwMatrix._parseLineNumber.ToString(), value);
                        }
                        case SwMatrix.SwitchCombinationFileError.UnexpectedCharacter:
                        {
                            return string.Format("Error loading Information from Line {0} of switch configuration file {1} - Unexpected Character", SwMatrix._parseLineNumber.ToString(), value);
                        }
                    }
                }
                else
                {
                    string error = string.Format("Error loading setting {0}", key);
                    return error;
                }
            }

            //Check if Communication Settings are defined
            if (P_TxPlcScanTime == 0)
            {
                string error = ("Transmitter Control PLC Scan Time not defined!");
                return error;
            }
            else
            {
                settingstext.WriteLine("Transmitter Control PLC Scan Time: {0} ms", P_TxPlcScanTime.ToString());
            }
            if (P_SwPlcScanTime == 0)
            {
                string error = ("Switch Matrix PLC Scan Time not defined!");
                return error;
            }
            else
            {
                settingstext.WriteLine("Switch Matrix PLC Scan Time: {0} ms", P_SwPlcScanTime.ToString());
            }
            if (P_SnmpScanTime == 0)
            {
                string error = ("SNMP Scan Time not defined!");
                return error;
            }
            else
            {
                settingstext.WriteLine("SNMP Scan Time: {0} ms", P_SnmpScanTime.ToString());
            }
            if (P_TxPLCIPAddress == null) 
            { 
                string error = ("Transmitter Control PLC IP Address not defined!"); 
                return error; 
            } 
            else 
            { 
                settingstext.Write("TxPLC IP Address: {0}", P_TxPLCIPAddress); 
            }
            if (P_SwPLCIPAddress == null)
            {
                string error = ("Switch Matrix PLC IP Address not defined!");
                return error;
            }
            else
            {
                settingstext.Write("SwPLC IP Address: {0}", P_SwPLCIPAddress);
            } 

            //Check if all otherTX  settings are defined
            foreach (SettingsTx newtxparam in P_TX.Values)
            {
                
                if (newtxparam.IPAddress.Length < 6)
                {
                    string error = string.Format("IP Address not defined!({0})", newtxparam.Name);
                    return error;
                }
                else
                {
                    settingstext.WriteLine("\r\n{0} IP Address: {1}", newtxparam.Name, newtxparam.IPAddress);
                }

                settingstext.Write("{0} Modulation Normal: ", newtxparam.Name);
                for (int i = 0; i < newtxparam.ModulationNormal.Length; i++)
                {
                    if (newtxparam.ModulationNormal[i] == Thompson.Tx.E_CommandModulationMode.Unknown)
                    {
                        string error = string.Format("Modulation Normal {0} type not defined!({1})", i.ToString(), newtxparam.Name);
                        return error;
                    }
                    else
                    {
                        settingstext.Write("[ARC+ {0} = {1}] ", i.ToString(), newtxparam.ModulationNormal[i].ToString());
                    }
                }
                settingstext.Write("\r\n{0} Modulation Generator: ", newtxparam.Name);
                for (int i = 0; i < newtxparam.ModulationGenerator.Length; i++)
                {
                    if (newtxparam.ModulationGenerator[i] == Thompson.Tx.E_CommandModulationMode.Unknown)
                    {
                        string error = string.Format("Modulation Generator {0} type not defined!({1})", i.ToString(), newtxparam.Name);
                        return error;
                    }
                    else
                    {
                        settingstext.Write("[ARC+ {0} = {1}] ", i.ToString(), newtxparam.ModulationGenerator[i].ToString());
                    }
                }
                settingstext.Write("\r\n{0} Power Normal: ", newtxparam.Name);
                for (int i = 0; i < newtxparam.PowerLevelNormal.Length; i++)
                {
                    if (newtxparam.PowerLevelNormal[i] == 999)
                    {
                        string error = string.Format("Power Level Normal {0} type not defined!({1})", i.ToString(), newtxparam.Name);
                        return error;
                    }
                    else
                    {
                        settingstext.Write("[ARC+ {0} = {1}] ", i.ToString(), newtxparam.PowerLevelNormal[i].ToString());
                    }
                }
                settingstext.Write("\r\n{0} Power Generator: ", newtxparam.Name);
                for (int i = 0; i < newtxparam.PowerLevelGenerator.Length; i++)
                {
                    if (newtxparam.PowerLevelGenerator[i] == 999)
                    {
                        string error = string.Format("Power Level Generator {0} type not defined!({1})", i.ToString(), newtxparam.Name);
                        return error;
                    }
                    else
                    {
                        settingstext.Write("[ARC+ {0} = {1}] ", i.ToString(), newtxparam.PowerLevelGenerator[i].ToString());
                    }
                }

            }

            //Settings were read successfully if it gets here
            success_b = true;
            return settingstext.ToString();     
        }

        private void MeterSelect_Click(object sender, EventArgs e)
        {
            // Per recommendation from Lance, Store everything when state changes, allowing
            // the program to perform faster updates
            foreach (var data in C_TX)
            {
                if (_selector[data.Key].Checked)
                {
                    _processMeters.Clear();
                    _processMeters.Add(new Meter(data.Value.MeasAudioInputLevelObj, pgAudioLevel, rdAudioLevel, Convert.ToInt32(pgAudioLevel.Tag), rdAudioLevel.Tag.ToString()));
                    _processMeters.Add(new Meter(data.Value.MeasRfGridCurrentObj, pgGridCurrent, rdGridCurrent, Convert.ToInt32(pgGridCurrent.Tag), rdGridCurrent.Tag.ToString()));
                    _processMeters.Add(new Meter(data.Value.MeasRfGridVoltageObj, pgGridVoltage, rdGridVoltage, Convert.ToInt32(pgGridVoltage.Tag), rdGridVoltage.Tag.ToString()));
                    _processMeters.Add(new Meter(data.Value.MeasRfPowerObj, pgUsefulPower, rdUsefulPower, Convert.ToInt32(pgUsefulPower.Tag), rdUsefulPower.Tag.ToString()));
                    _processMeters.Add(new Meter(data.Value.MeasRfDifferentialTemperatureObj, pgDiffTemp, rdDiffTemp, Convert.ToInt32(pgDiffTemp.Tag), rdDiffTemp.Tag.ToString()));
                    _processMeters.Add(new Meter(data.Value.MeasRfAnodeCurrentObj, pgAnodeCurrent, rdAnodeCurrent, Convert.ToInt32(pgAnodeCurrent.Tag), rdAnodeCurrent.Tag.ToString()));
                    _processMeters.Add(new Meter(data.Value.MeasRfScreenCurrentObj, pgScreenCurrent, rdScreenCurrent, Convert.ToInt32(pgScreenCurrent.Tag), rdScreenCurrent.Tag.ToString()));
                    _processMeters.Add(new Meter(data.Value.MeasRfAnodeVoltageObj, pgAnodeVoltage, rdAnodeVoltage, Convert.ToInt32(pgAnodeVoltage.Tag), rdAnodeVoltage.Tag.ToString()));
                    _processMeters.Add(new Meter(data.Value.MeasRfMainsVoltageObj, pgMainsVoltage, rdMainsVoltage, Convert.ToInt32(pgMainsVoltage.Tag), rdMainsVoltage.Tag.ToString()));
                    _processMeters.Add(new Meter(data.Value.MeasVSWRObj, pgVswr, rdVswr, Convert.ToInt32(pgVswr.Tag), rdVswr.Tag.ToString()));
                    _processMeters.Add(new Meter(data.Value.MeasReflectedPowerObj, pgReflectedPower, rdReflectedPower, Convert.ToInt32(pgReflectedPower.Tag), rdReflectedPower.Tag.ToString()));
                    break;
                }
            }
        }

        private void StartWindow_FormClosed(object sender, FormClosedEventArgs e)
        {
            log.Write("Application closed");
            if (SwPLC.tmrScanPLC != null)
            {
                SwPLC.tmrScanPLC.Dispose();
            }
            if (TxPLC.tmrScanPLC != null)
            {
                TxPLC.tmrScanPLC.Dispose();
            }
            foreach (Thompson.Tx Tx in C_TX.Values)
            {
                Tx.tmrScanTx.Dispose();
            }
            if (txSwitcher != null)
            {
                if (txSwitcher._previewPane != null)
                {
                    txSwitcher._previewPane.Close();
                }
                txSwitcher.Close();
            }
            // kill these 'newed' objects
            //PlcComm TxPLC = new PlcComm();
            //PlcComm SwPLC = new PlcComm();
        }

        private void btnRestart_Click(object sender, EventArgs e)
        {
            log.Write("Application is restarted");
            P_TX.Clear();
            C_TX.Clear();
            G_TX.Clear();
            initInterface();

        }

        
        /// <summary>
        /// Return the current version. If running the deployed version, returns that version number,
        /// otherwise returns the assembly version.
        /// </summary>
        /// <returns>Version number</returns>
        private string swVersion()
        {
            string ourVersion = string.Empty;
            
            string assemName = Assembly.GetEntryAssembly().GetName().Name.ToString(); 
            //if running the deployed application, you can get the version
            //  from the ApplicationDeployment information. If you try
            //  to access this when you are running in Visual Studio, it will not work.
            
            if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
                ourVersion = ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString();
            else
            {
                System.Reflection.Assembly assemblyInfo = System.Reflection.Assembly.GetExecutingAssembly();
                if (assemblyInfo != null)
                    ourVersion = string.Format("{0} (Not Deployed)", assemblyInfo.GetName().Version.ToString());
            }
            return string.Format("{0} Version: {1}",assemName,ourVersion);
        }

        

        private void btnEditConfig_Click(object sender, EventArgs e)
        {
            string cfgFile = ".\\ThompsonTxInterface.exe.config";
            System.Diagnostics.Process.Start(@"notepad.exe", cfgFile);
        }

        
        private void btnShowLog_Click(object sender, EventArgs e)
        {
            string cfgFile = ".\\LogFiles";
            System.Diagnostics.Process.Start(@"explorer.exe", cfgFile);
        }

        public string PublishVersion
        {
            get
            {
                Assembly assem = Assembly.GetExecutingAssembly();
                AssemblyName assemName = assem.GetName();
                Version ver = assemName.Version;
                return string.Format("Version {0}.{1}.{2}.{3}", ver.Major, ver.Minor, ver.Build, ver.Revision);
            }
        }

        // This command Updates the SwitchMatrix Display
        private void SwitchMatrixTimer_Tick(object sender, EventArgs e)
        {
            // Only Update if the Switch Matrix Tab is active
            // Note: This may have to go away in the future, but
            // for now, it is only necessary to update the display when
            // it is active
            bool updateActive = true;
            // make sure that txSwitcher is defined before performing check for
            // preview pane.
            if (txSwitcher != null)
            {
                if (txSwitcher._previewPane != null)
                {
                    if (txSwitcher._previewPane.Visible)
                    {
                        updateActive = false;
                    }
                }
            }
            if (SwitchMatrix.Visible && updateActive)
            {
                //_txColor[0] = Color.Black;
                //_txColor[1] = Color.Magenta;
                //_txColor[2] = Color.Red;
                //_txColor[3] = Color.Black;
                //_txColor[4] = Color.Black;
                //_txColor[5] = Color.Yellow;
                //_txColor[6] = Color.Cyan;
                //_txColor[7] = Color.Blue;
                Transmitter6.BackColor = SwMatrix._txColor[6];
                Transmitter2.BackColor = SwMatrix._txColor[2];
                Transmitter1.BackColor = SwMatrix._txColor[1];
                Transmitter7.BackColor = SwMatrix._txColor[7];
                Transmitter5.BackColor = SwMatrix._txColor[5];
                TX6toSW1_1.BackColor = SwMatrix._txColor[6];
                TX6toSW1_2.BackColor = SwMatrix._txColor[6];
                TX6toSW1_3.BackColor = SwMatrix._txColor[6];
                TX2toSW1_1.BackColor = SwMatrix._txColor[2];
                TX2toSW1_2.BackColor = SwMatrix._txColor[2];
                TX1toSW2_1.BackColor = SwMatrix._txColor[1];
                TX1toSW2_2.BackColor = SwMatrix._txColor[1];
                TX1toSW2_3.BackColor = SwMatrix._txColor[1];
                TX7toSW2_1.BackColor = SwMatrix._txColor[7];
                TX7toSW2_2.BackColor = SwMatrix._txColor[7];
                TX5toSW3_1.BackColor = SwMatrix._txColor[5];
                TX5toSW3_2.BackColor = SwMatrix._txColor[5];
                SwMatrix.CalculateTransmitterFeeds(SwMatrix._switchPositions);
                // track current Switch (makes copy/paste easier)
                byte currentSwitch = 0;
                // Switch 1 Outputs
                SW1toSW4_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW1toSW4_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW1toSW4_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW1toSW6_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW1toSW6_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch1.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch1.Load();
                // Switch 2 Outputs
                SW2toSW3_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW2toSW3_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW2toSW3_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW2toSW4_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW2toSW4_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW2toSW4_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch2.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch2.Load();
                // Switch 3 Outputs
                SW3toSW8_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW3toSW8_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW3toSW8_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW3toSW8_4.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW3toSW5_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW3toSW5_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW3toSW5_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch3.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch3.Load();
                // Switch 4 Outputs
                SW4toSW5_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW4toSW5_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW4toSW5_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW4toSW6_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW4toSW6_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW4toSW6_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch4.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch4.Load();
                // Switch 5 Outputs
                SW5toSW8_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW5toSW8_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW5toSW8_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW5toSW7_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW5toSW7_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW5toSW7_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch5.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch5.Load();
                // Switch 6 Outputs
                SW6toSW7_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW6toSW7_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW6toSW7_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW6toSW9_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW6toSW9_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch6.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch6.Load();
                // Switch 7 Outputs
                SW7toSW10_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW7toSW10_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW7toSW10_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW7toSW9_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW7toSW9_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW7toSW9_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch7.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch7.Load();
                // Switch 8 Outputs
                SW8toANT4_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW8toANT4_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW8toANT4_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW8toSW11_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW8toSW11_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW8toSW11_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch8.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch8.Load();
                // Switch 9 Outputs
                SW9toANT2A_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW9toANT2A_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW9toANT2A_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW9toANT2A_4.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW9toANT2A_5.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW9toANT1_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW9toANT1_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch9.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch9.Load();
                // Switch 10 Outputs
                SW10toLOAD_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW10toLOAD_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW10toLOAD_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW10toLOAD_4.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW10toLOAD_5.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW10toANT3_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW10toANT3_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch10.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch10.Load();
                // Switch 11 Outputs
                SW11toANT2B_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW11toANT2B_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW11toANT2B_3.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 0)];
                SW11toANT5_1.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                SW11toANT5_2.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(currentSwitch, 1)];
                Switch11.ImageLocation = SwMatrix._imageLocations[currentSwitch++];
                Switch11.Load();
                // Antennas
                Antenna1.BackColor =  SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(8, 1)];
                Antenna2A.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(8, 0)];
                Antenna3.BackColor =  SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(9, 1)];
                DummyLoad.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(9, 0)];
                Antenna5.BackColor =  SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(10, 1)];
                Antenna2B.BackColor = SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(10, 0)];
                Antenna4.BackColor =  SwMatrix._txColor[SwMatrix.TransmitterFeedingSegment(7, 0)];
            }
            else if (TxControlTab.Visible)
            {
                foreach (int key in G_TX.Keys)
                {
                    TxUsrCtrl ctrl = G_TX[key];
                    //Update the Gui with the current text if the Transmitter is not accessing
                    //the text at this moment.
                    C_TX[key]._txMutex.WaitOne();
                    ctrl.WriteSnmpStatus(C_TX[key]._guiText);
                    C_TX[key]._txMutex.ReleaseMutex();
                }

            }
            TxPLC._txPlcReadMutex.WaitOne();
            TxPLC._txPlcWriteMutex.WaitOne();
            foreach (int key in C_TX.Keys)
            {
                C_TX[key]._txMutex.WaitOne();
                //Update the PLC with the Heating info
                TxPLC.WriteHeating(key, C_TX[key]._plcHeating);

                //Update the PLC with the Alarm info
                TxPLC.WriteAlarm(key, C_TX[key]._plcAlarm);

                //Update the Transmitter Status
                P_TX[key].Command = (Thompson.Tx.E_CommandTx)C_TX[key]._command;
                
                P_TX[key].Channel = C_TX[key]._channel;

                P_TX[key].PowerLevel = C_TX[key]._powerLevel;

                if (TxPLC._requests[key].GenModulation)
                {
                    for (byte x = 0; x < P_TX[key].ModulationGenerator.Length; x++)
                    {
                        if ((byte)P_TX[key].ModulationGenerator[x] == C_TX[key]._modulation)
                        {
                            P_TX[key].Modulation = x;
                        }
                    }
                }
                else
                {
                    for (byte x = 0; x < P_TX[key].ModulationNormal.Length; x++)
                    {
                        if ((byte)P_TX[key].ModulationNormal[x] == C_TX[key]._modulation)
                        {
                            P_TX[key].Modulation = x;
                        }
                    }
                }
                C_TX[key]._txMutex.ReleaseMutex();
            }
            TxPLC._txPlcWriteMutex.ReleaseMutex();
            foreach (int key in P_TX.Keys)
            {
                C_TX[key]._txMutex.WaitOne();
                try
                {
                    //Update Gui with the PLC results
                    G_TX[key].updateDisplay(TxPLC._requests[key], P_TX[key]);
                    //Update the requests in the Transmitter
                    C_TX[key].SetNewCommands(TxPLC._requests[key], P_TX[key]);
                }
                // Because _requests is only updated if valid data is received from the
                // PLC, the above updates will return an exception.
                catch (Exception)
                {
                    //Gets here if a null value is received
                }
                C_TX[key]._txMutex.ReleaseMutex();
            }
            TxPLC._txPlcReadMutex.ReleaseMutex();
            TxPlcStatus.ForeColor = TxPLC._guiTextForeColor;
            TxPlcStatus.Text = TxPLC._guiText;
            SwPlcStatus.ForeColor = SwPLC._guiTextForeColor;
            SwPlcStatus.Text = SwPLC._guiText;
            // Note: This code does not belong for the final version.
            // it does permit updating the switch status based on desired configuration
            // and is required until the actual switch matrix is in place.
#if PROTOTYPE
            // <KLUDGE>            
            for (byte x = 0; x < 11; x++)
            {
                if (SwMatrix._targetSwitchPositions[x] != _oldTargetSwitchPositions[x])
                {
                    if (SwMatrix._targetSwitchPositions[x])
                    {
                        SwMatrix._switchPositions[x] = 1;
                    }
                    else
                    {
                        SwMatrix._switchPositions[x] = 0;
                    }
                }
                _oldTargetSwitchPositions[x] = SwMatrix._targetSwitchPositions[x];
            }
            //</KLUDGE>
#endif
            //Update Flasher
            if (Flasher.BackColor == System.Drawing.SystemColors.Control)
            {
                Flasher.BackColor = Color.LightGreen;
            }
            else
            {
                Flasher.BackColor = System.Drawing.SystemColors.Control;
            }
            // Update Meters
            if (MeterPage.Visible)
            {
                if (!_meterPageWasVisible)
                {
                    MeterSelect_Click(new object(), new EventArgs());
                }
                foreach (Meter meter in _processMeters)
                {
                    meter.Update();
                }
            }
            _meterPageWasVisible = MeterPage.Visible;
        }

        // This logic allows updating the perceived switch position to reflect the
        // position selected by the user by clicking on the boxes.
        //<KLUDGE>
#if PROTOTYPE
        private void Switch1_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[0] = 0;
            if (SwMatrix._switchPositions[0] > 1)
            {
                SwMatrix._switchPositions[0] = 0;
            }
            else
            {
                SwMatrix._switchPositions[0]++;
            }
        }

        private void Switch2_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[1] = 0;
            if (SwMatrix._switchPositions[1] > 1)
            {
                SwMatrix._switchPositions[1] = 0;
            }
            else
            {
                SwMatrix._switchPositions[1]++;
            }
        }

        private void Switch3_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[2] = 0;
            if (SwMatrix._switchPositions[2] > 1)
            {
                SwMatrix._switchPositions[2] = 0;
            }
            else
            {
                SwMatrix._switchPositions[2]++;
            }
        }

        private void Switch4_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[3] = 0;
            if (SwMatrix._switchPositions[3] > 1)
            {
                SwMatrix._switchPositions[3] = 0;
            }
            else
            {
                SwMatrix._switchPositions[3]++;
            }
        }

        private void Switch5_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[4] = 0;
            if (SwMatrix._switchPositions[4] > 1)
            {
                SwMatrix._switchPositions[4] = 0;
            }
            else
            {
                SwMatrix._switchPositions[4]++;
            }
        }

        private void Switch6_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[5] = 0;
            if (SwMatrix._switchPositions[5] > 1)
            {
                SwMatrix._switchPositions[5] = 0;
            }
            else
            {
                SwMatrix._switchPositions[5]++;
            }
        }

        private void Switch7_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[6] = 0;
            if (SwMatrix._switchPositions[6] > 1)
            {
                SwMatrix._switchPositions[6] = 0;
            }
            else
            {
                SwMatrix._switchPositions[6]++;
            }
        }

        private void Switch8_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[7] = 0;
            if (SwMatrix._switchPositions[7] > 1)
            {
                SwMatrix._switchPositions[7] = 0;
            }
            else
            {
                SwMatrix._switchPositions[7]++;
            }
        }

        private void Switch9_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[8] = 0;
            if (SwMatrix._switchPositions[8] > 1)
            {
                SwMatrix._switchPositions[8] = 0;
            }
            else
            {
                SwMatrix._switchPositions[8]++;
            }
        }

        private void Switch10_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[9] = 0;
            if (SwMatrix._switchPositions[9] > 1)
            {
                SwMatrix._switchPositions[9] = 0;
            }
            else
            {
                SwMatrix._switchPositions[9]++;
            }
        }

        private void Switch11_Click(object sender, EventArgs e)
        {
            //SwPlcComm.SwMatrixPlc_CoilsRead[10] = 0;
            if (SwMatrix._switchPositions[10] > 1)
            {
                SwMatrix._switchPositions[10] = 0;
            }
            else
            {
                SwMatrix._switchPositions[10]++;
            }
        }
        //</KLUDGE>
#endif
        private void CfgTxSettings_Click(object sender, EventArgs e)
        {
            // Eventually this will open a dialog allowing the user to set
            // transmitter routing preferences
            txSwitcher = new TxSwitcher();
            // Update Data for actual Switch Position
            SwMatrix.CalculateTransmitterFeeds(SwMatrix._switchPositions);

            // Update Antenna Configuration to Default
            for (byte x = 0; x <= SwMatrix.MaximumTransmitterNumber; x++)
            {
                SwMatrix._antennaSelected[x] = SwMatrix._antennaConnected[x];
            }

            //txSwitcher.UpdateDisplay = UpdateConfigDisplay;
            txSwitcher.ShowDialog();
        }

        private void StartWindow_Load(object sender, EventArgs e)
        {

        }

        private void Flasher_Click(object sender, EventArgs e)
        {

        }
    }
}

public class SettingsTx
{
    public Thompson.Tx.E_CommandModulationMode[] ModulationNormal { get; set; }
    public Thompson.Tx.E_CommandModulationMode[] ModulationGenerator { get; set; }
    public int[] PowerLevelNormal { get; set; }
    public int[] PowerLevelGenerator { get; set; }
    public byte PowerLevel { get; set; }
    public byte Modulation { get; set; }
    public byte Channel { get; set; }
    public Thompson.Tx.E_CommandTx Command { get; set; }
    public string IPAddress { get; set; }
    public string Name { get; set; }
}

// Information for Metering Screen
public class Meter
{
    public Thompson.TxItem _tag;
    public ProgressBar _display;
    public int _divider;
    public Label _readout;
    public String _unit;

    public Meter(Thompson.TxItem tag, ProgressBar display, Label readout = null, int divider = 1, string unit = "")
    {
        _tag = tag;
        _display = display;
        _readout = readout;
        _divider = divider;
        _unit = unit;
    }

    public void Update()
    {
        int temp = _tag.CurrentValue;
        // Avoid Divide by Zero
        if (_divider < 1)
        {
            _divider = 1;
        }
        // Make Sure that the correct number of decimal places are displayed
        int multiplier = 1;
        string format = "N";
        for (byte x = 0; x < 8; x++)
        {
            if (_divider <= multiplier)
            {
                format += x.ToString();
                break;
            }
            multiplier *= 10;
        }
        // Display the value if Text Box provided
        if (_readout != null)
        {
            _readout.Text = (Convert.ToDouble(temp) / Convert.ToDouble(_divider)).ToString(format) + " " + _unit;
        }
        // Display on the graph
        if (temp < _display.Minimum)
        {
            temp = _display.Minimum;
        }
        else if (temp > _display.Maximum)
        {
            temp = _display.Maximum;
        }
        _display.Value = temp;
    }
}
